package haust;

import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;

/*
 *  3D Vector Class 
 */
public class Vec3
{
	/**
	 * Sets (x,y,z) to 0.0f
	 */
	public Vec3()
	{
		values.put(0, 0.0f);
		values.put(1, 0.0f);
		values.put(2, 0.0f);
	}
	
	/**
	 * 
	 * @param x
	 * @param y
	 * @param z
	 */
	public Vec3(float x, float y, float z)
	{
		values.put(0, x);
		values.put(1, y);
		values.put(2, z);
	}
	
	/**
	 * 
	 * @param v
	 */
	public Vec3( Vec3 v )
	{
		set(v);
	}
	
	
	/**
	 * Add v to this instance
	 * @param v
	 */
	public void add( Vec3 v )
	{
		setX( getX() + v.getX() );
		setY( getY() + v.getY() );
		setZ( getZ() + v.getZ() );
	}
	
	/**
	 * Subtract v from this instance.
	 * @param v
	 */
	public void subtract(Vec3 v) 
	{
		setX( getX() - v.getX() );
		setY( getY() - v.getY() );
		setZ( getZ() - v.getZ() );
	}
	
	/**
	 * Rotates the vector around the axis formed by (x,y,z)
	 * This method uses Quaternions to rotate
	 * Using the formula: v' = qr * v * qr^-1
	 * 
	 * The inverse of a quaternion is the same as the conjugation of a quaternion
	 * see: Vec4.conjugate()
	 * 
	 * @param a angle in radians
	 * @param x 
	 * @param y
	 * @param z
	 */
	public void rotate(float a, float x, float y, float z)
	{
		Vec4 qr = new Vec4();		
		qr.rotate(a,x,y,z);
		
		Vec4 qri = new Vec4(qr);
		qri.conjugate(); //inverse

		Vec4 temp = new Vec4();
		
		//temp = qr*v
		temp.multiply(qr, new Vec4(getX(), getY(), getZ(), 0.0f));
		
		Vec4 rot = new Vec4();
		//v = (qr*v) * qr^-1
		rot.multiply(temp, qri); 
	
		setX(rot.getX());
		setY(rot.getY());
		setZ(rot.getZ());
	}
	
	/**
	 * 
	 * @return (vectorlength)^2
	 */
	public float squaredlength() 
	{
		return getX()*getX() + getY()*getY() + getZ()*getZ();
	}
	
	/**
	 * 
	 */
	public void normalize()
	{
		float dot = getX()*getX() + getY()*getY() + getZ()*getZ();
		float length = (float)Math.sqrt(dot);
		
		if( Math.abs(length) > 0.0001f )
		{
			setX( getX() / length );
			setY( getY() / length );
			setZ( getZ() / length );
		}
	}
	
	/**
	 * Calculates and stores the Cross product of v1 and v2 in this instance
	 * 
	 * @param v1
	 * @param v2
	 */
	public void cross( Vec3 v1, Vec3 v2 )
	{
	   setX((v1.getY() * v2.getZ()) - (v1.getZ() * v2.getY()));
	   setY((v1.getZ() * v2.getX()) - (v1.getX() * v2.getZ()));
	   setZ((v1.getX() * v2.getY()) - (v1.getY() * v2.getX()));		
	}
	
	public float getX() { return values.get(0); }
	public float getY() { return values.get(1); }
	public float getZ() { return values.get(2); }
	public void setX(float val)  { values.put(0, val); }
	public void setY(float val)  { values.put(1, val); }
	public void setZ(float val)  { values.put(2, val); }
	public void zero() { values.put(0,0); values.put(1,0.0f); values.put(2,0.0f); }
	
	/**
	 * 
	 * @param v Vector to copy and store in this instance
	 */
	public void set(Vec3 v) 
	{
		values.put(0, v.getX());
		values.put(1, v.getY());
		values.put(2, v.getZ());
	}
	
	/**
	 * Scales the vector by value
	 * @param scalar 
	 */
	public void scale( float scalar )
	{
		setX( getX() * scalar );
		setY( getY() * scalar );
		setZ( getZ() * scalar );
	}
	
	/**
	 * 
	 * @return this instances FloatBuffer
	 */
	public FloatBuffer get()
	{
		return values;
	}
	
	private FloatBuffer values = BufferUtils.createFloatBuffer(3);
} 